package com.prim.threadpool;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 手写一个线程池
 *
 * @author prim
 */
public class FixedSizeThreadPool {
    //需要准备哪些工作？
    /**
     * 等待任务仓库队列 双端阻塞队列
     */
    private BlockingDeque<Runnable> blockingDeque;

    /**
     * 存储工作的线程
     */
    private List<Thread> works;

    /**
     * 执行任务
     */
    private static class Work extends Thread {
        FixedSizeThreadPool pool;

        public Work(FixedSizeThreadPool pool) {
            this.pool = pool;
        }

        @Override
        public void run() {
            while (this.pool.isWorking || this.pool.blockingDeque.size() > 0) {
                Runnable task = null;
                try {
                    if (this.pool.isWorking) {
                        //阻塞 等待队列中插入任务执行
                        task = this.pool.blockingDeque.take();
                    } else {
                        //非阻塞
                        task = this.pool.blockingDeque.poll();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //有任务提交 执行任务
                if (task != null) {
                    task.run();
                }
            }
        }
    }

    /**
     * 4 初始化线程池
     *
     * @param corePoolSize 核心线程数
     * @param queueSize    等待任务队列数
     */
    public FixedSizeThreadPool(int corePoolSize, int queueSize) {
        if (corePoolSize <= 0 || queueSize <= 0) {
            throw new IllegalArgumentException("非法参数");
        }
        blockingDeque = new LinkedBlockingDeque<>(queueSize);
        works = Collections.synchronizedList(new ArrayList<>());
        //创建设置核心线程数的线程
        for (int i = 0; i < corePoolSize; i++) {
            Work work = new Work(this);
            work.start();//启动worker对象 实际上就是启动一个线程
            works.add(work);
        }
    }

    //5 对外提供提交任务的接口
    // 非阻塞
    public boolean submit(Runnable runnable) {
        if (isWorking) {
            return blockingDeque.offer(runnable);
        } else {
            return false;
        }
    }

    // 阻塞
    public void execute(Runnable runnable) {
        if (isWorking) {
            try {
                blockingDeque.put(runnable);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 关闭线程池
     * 1. 禁止往队列中提交任务
     * 2. 等待仓库中的任务执行完毕
     * 3. 关闭的时候，再去拿任务不用阻塞，因为不会有新任务来了
     * 4. 关闭的时候，阻塞的线程就要抢行中止
     */
    private volatile boolean isWorking = true;

    public void shutdown() {
        this.isWorking = false;
        for (Thread work : works) {
            if (work.getState().equals(Thread.State.WAITING) ||
                    work.getState().equals(Thread.State.BLOCKED)) {
                work.interrupt();
            }
        }
    }

}
